package com.jy.datapipeline.export.service.impl;

import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.util.ListUtils;
import com.jy.datapipeline.common.constants.ExpConstants;
import com.jy.datapipeline.common.util.AssertUtil;
import com.jy.datapipeline.common.util.ConvertUtil;
import com.jy.datapipeline.common.util.StringUtil;
import com.jy.datapipeline.export.dao.ExpRuleDao;
import com.jy.datapipeline.export.dao.repo.ExpRuleDaoRepo;
import com.jy.datapipeline.export.entity.*;
import com.jy.datapipeline.export.service.ExpRuleDetailService;
import com.jy.datapipeline.export.service.ExpRuleService;
import com.jy.datapipeline.common.util.SnowFlakeUtil;
import com.mysql.cj.util.StringUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.analysis.function.Exp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service("expRuleService")
@Transactional
@Slf4j
public class ExpRuleServiceImpl implements ExpRuleService {
    @Autowired
    private ExpRuleDao expRuleDao;
    @Autowired
    private ExpRuleDaoRepo expRuleDaoRepo;

    @Resource
    private ExpRuleDetailService expRuleDetailService;

    @Override
    public List<Map<String, Object>> findExpRuleByList(String dataSourceName, String ruleName,
        Integer iDisplayStart, Integer iDisplayLength) {

        return this.expRuleDao.findExpRuleByList(dataSourceName,ruleName,iDisplayStart,iDisplayLength);
    }

    @Override
    public int findExpRuleByCount(String dataSourceName, String ruleName) {
        return this.expRuleDao.findExpRuleByCount(dataSourceName,ruleName);
    }

    @Override
    public boolean updateExpRule(ExpRuleModel erm) {

        return this.expRuleDao.updateExpRule(erm);
    }

    @Override
    public ExpRuleModel findByRuleName(String ruleName) {

        return this.expRuleDaoRepo.findByRuleName(ruleName);
    }

    @Override
    public ExpRuleModel findByRuleId(String ruleId) {
        return this.expRuleDaoRepo.findByRuleId(ruleId);
    }

    @Override
    public boolean saveExpRule(ExpRuleModel expRuleModel) {
        this.expRuleDaoRepo.save(expRuleModel);
        return true;
    }

    @Override
    public boolean deleteExpRule(int id) {
        this.expRuleDaoRepo.deleteById(id);
        return true;
    }

    @Override
    public boolean deleteByRuleId(String ruleId) {
        return this.expRuleDao.deleteByRuleId(ruleId);
    }

    @Override
    public List<Map<String, Object>> findRuleInfoByTask(String ruleId, int status) {
        return this.expRuleDao.findRuleInfoByTask(ruleId,status);
    }

    @Override
    public List<ExpRuleModel> findByDataSourceId(String dataSourceId) {
        return this.expRuleDaoRepo.findByDataSourceId(dataSourceId);
    }

    private void checkIsNull(RuleTemplateModel ruleTemplateModel) {
        AssertUtil.isNull(ruleTemplateModel.getRuleName(), ExpConstants.EXP_RULE_NAME_IS_NULL);
        AssertUtil.isNull(ruleTemplateModel.getRuleType(), ExpConstants.EXP_RULE_TYPE_IS_NULL);
        AssertUtil.isNull(ruleTemplateModel.getRuleTbl(), ExpConstants.EXP_RULE_TBL_IS_NULl);
        AssertUtil.isNull(ruleTemplateModel.getRuleTblType(), ExpConstants.EXP_RULE_TBL_TYPE_IS_NULL);
        AssertUtil.isNull(ruleTemplateModel.getDataUnit(), ExpConstants.EXP_RULE_DATA_UNIT_IS_NULL);
        AssertUtil.isNull(ruleTemplateModel.getDataPeriod(), ExpConstants.EXP_RULE_DATA_PERIOD_IS_NULL);
        AssertUtil.isNull(ruleTemplateModel.getColList(), ExpConstants.EXP_RULE_COL_LIST_IS_NULL);
        AssertUtil.isNull(ruleTemplateModel.getColSeparator(), ExpConstants.EXP_RULE_COL_SEPERATOR_IS_NULL);
        AssertUtil.isNull(ruleTemplateModel.getDataSourceId(), ExpConstants.EXP_RULE_DATA_SOURCE_IS_NULL);
        AssertUtil.isNull(ruleTemplateModel.getSchemaName(), ExpConstants.EXP_RULE_SCHEMA_IS_NULL);
        AssertUtil.isNull(ruleTemplateModel.getRuleTblSuffix(), ExpConstants.EXP_DYNAMIC_RULE_TBL_IS_NULL);

    }

    @Override
    public <T> T analysisExcelRows(T data) {
        RuleTemplateModel ruleTemplateModel = ConvertUtil.convertObject(data, RuleTemplateModel.class);

        //是否为空校验
        this.checkIsNull(ruleTemplateModel);

        //规则名称是否重复
        ExpRuleModel expRuleModel = this.expRuleDaoRepo.findByRuleName(ruleTemplateModel.getRuleName());
        AssertUtil.isNotNUll(expRuleModel, ExpConstants.EXP_RULE_IS_EXISTS);

        //表类型校验
        int ruleTblType;
        try {
            ruleTblType = Integer.parseInt(ruleTemplateModel.getRuleTblType());
            if (ruleTblType != 1 && ruleTblType != 0) {
                throw new ExcelAnalysisStopException("表类型只能是0或1");
            }
        } catch (Exception e) {
            throw new ExcelAnalysisStopException("表类型只能是数值型数据");
        }

        //动态规则校验
        if (ruleTblType == 1) {
            String ruleTblSuffix = ruleTemplateModel.getRuleTblSuffix();
            if (ruleTblSuffix == null) {
                throw new ExcelAnalysisStopException("动态表中动态表规则不能为空");
            }
            if (!ruleTblSuffix.equals("ADDMONTHS") && !ruleTblSuffix.equals("YYYY") && !ruleTblSuffix.equals("YYYYMM")) {
                throw new ExcelAnalysisStopException("动态表规则只能是ADDMONTHS、YYYY、YYYYMM");
            }
            if (ruleTblSuffix.toUpperCase(Locale.ROOT).equals("ADDMONTHS")) {
                String funValue = ruleTemplateModel.getFunValue();
                if (StringUtils.isNullOrEmpty(funValue)) {
                    throw new ExcelAnalysisStopException("规则为ADDMONTHS的动态表中函数值不能为空");
                }
            }
        }

        //数据周期单位校验
        String dataUnit = ruleTemplateModel.getDataUnit();
        if (!dataUnit.equals("Y") && !dataUnit.equals("M") && !dataUnit.equals("D") && !dataUnit.equals("H") && !dataUnit.equals("MI")) {
            throw new ExcelAnalysisStopException("数据周期单位只能是Y、M、D、H、MI");
        }
        String dataPeriod = ruleTemplateModel.getDataPeriod();
        if (!StringUtils.isNullOrEmpty(dataUnit) && StringUtils.isNullOrEmpty(dataPeriod)) {
            throw new ExcelAnalysisStopException("存在数据周期的同时数据间隔不能为空");
        }

        //值类型校验
        if (!StringUtil.isNumber(dataPeriod)) {
            throw new ExcelAnalysisStopException("数据间隔值只能为数值型数据");
        }

        //过滤规则校验
        try {
            int ruleType = Integer.parseInt(ruleTemplateModel.getRuleType());
            if (ruleType != 1 && ruleType != 2 && ruleType != 3) {
                throw new ExcelAnalysisStopException("过滤规则的值只能为1，2，3");
            }
        } catch (Exception e) {
            throw new ExcelAnalysisStopException("过滤规则的值只能是数值型数据");
        }

        //值类型校验
        if (!StringUtil.isNumber(ruleTemplateModel.getInitRow())) {
            throw new ExcelAnalysisStopException("单文件最大行数只能为数值型数据");
        }

        return (T) ruleTemplateModel;
    }

    @Transactional
    @Override
    public <T> Set<Long> batchSave(List<T> t) throws Exception {
        List<RuleTemplateModel> ruleTemplateModelList = ConvertUtil.convertArray(t, RuleTemplateModel.class);
        List<ExpRuleModel> expRuleModelList = ListUtils.newArrayList();
        List<ExpRuleDetailModel> expRuleDetailModelList = ListUtils.newArrayList();

        ExpRuleModel expRuleModel;
        ExpRuleDetailModel expRuleDetailModel;
        for (RuleTemplateModel ruleTemplateModel : ruleTemplateModelList) {
            expRuleModel = new ExpRuleModel();
            String ruleId = "rule_" + SnowFlakeUtil.getNextId();
            expRuleModel.setRuleId(ruleId);
            expRuleModel.setRuleName(ruleTemplateModel.getRuleName());
            expRuleModel.setDataSourceId(ruleTemplateModel.getDataSourceId());
            expRuleModel.setColSeparator(ruleTemplateModel.getColSeparator());
            expRuleModel.setUpdate_time(new Date());
            expRuleModel.setIsFile(1);
            expRuleModelList.add(expRuleModel);

            expRuleDetailModel = new ExpRuleDetailModel();
            int ruleTblType = Integer.parseInt(ruleTemplateModel.getRuleTblType());
            if (ruleTblType == 1) {
                String ruleTblSuffix = ruleTemplateModel.getRuleTblSuffix();
                switch (ruleTblSuffix.toUpperCase(Locale.ROOT)) {
                    case "YYYY":
                    case "YYYYMM":
                        expRuleDetailModel.setRuleTblSuffix(ruleTblSuffix);
                        break;
                    case "ADDMONTHS":
                        expRuleDetailModel.setRuleTblSuffix(ruleTblSuffix);
                        expRuleDetailModel.setFunValue(Integer.parseInt(ruleTemplateModel.getFunValue()));
                        break;
                }
            }

            expRuleDetailModel.setRuleTblType(ruleTblType);
            expRuleDetailModel.setDataUnit(ruleTemplateModel.getDataUnit());
            expRuleDetailModel.setDataPeriod(Integer.parseInt(ruleTemplateModel.getDataPeriod()));
            expRuleDetailModel.setSchemaName(ruleTemplateModel.getSchemaName());
            expRuleDetailModel.setRuleTbl(ruleTemplateModel.getRuleTbl());
            expRuleDetailModel.setColList(ruleTemplateModel.getColList());
            expRuleDetailModel.setRuleTYpe(Integer.parseInt(ruleTemplateModel.getRuleType()));
            expRuleDetailModel.setRowRange(ruleTemplateModel.getRowRange());
            expRuleDetailModel.setSplitKey(ruleTemplateModel.getSplitKey());
            expRuleDetailModel.setInitRow(Integer.parseInt(ruleTemplateModel.getInitRow()));
            expRuleDetailModel.setRuleDetailId("rule_detail_" + SnowFlakeUtil.getNextId());
            expRuleDetailModel.setUpdate_time(new Date());
            expRuleDetailModel.setRuleId(ruleId);
            expRuleDetailModelList.add(expRuleDetailModel);
        }

        Set<Integer> idSet = expRuleDao.batchSave(expRuleModelList);
        expRuleDetailService.batchSave(expRuleDetailModelList);

        Set<Long> ids = new HashSet<>();
        for (Integer id : idSet) {
            ids.add((long) id);
        }

        return ids;
    }

    @Transactional
    @Override
    public <T> Long save(T t) {
        RuleTemplateModel ruleTemplateModel = ConvertUtil.convertObject(t, RuleTemplateModel.class);

        //添加expRuleModel
        ExpRuleModel expRuleModel = new ExpRuleModel();
        String ruleId = "rule_" + SnowFlakeUtil.getNextId();
        expRuleModel.setRuleId(ruleId);
        expRuleModel.setRuleName(ruleTemplateModel.getRuleName());
        expRuleModel.setDataSourceId(ruleTemplateModel.getDataSourceId());
        expRuleModel.setColSeparator(ruleTemplateModel.getColSeparator());
        expRuleModel.setUpdate_time(new Date());
        expRuleModel.setIsFile(1);

        expRuleDaoRepo.save(expRuleModel);

        //添加expRuleDetailModel
        ExpRuleDetailModel expRuleDetailModel = new ExpRuleDetailModel();
        int ruleTblType = Integer.parseInt(ruleTemplateModel.getRuleTblType());
        if (ruleTblType == 1) {
            String ruleTblSuffix = ruleTemplateModel.getRuleTblSuffix();
            switch (ruleTblSuffix.toUpperCase(Locale.ROOT)) {
                case "YYYY":
                case "YYYYMM":
                    expRuleDetailModel.setRuleTblSuffix(ruleTblSuffix);
                    break;
                case "ADDMONTHS":
                    expRuleDetailModel.setRuleTblSuffix(ruleTblSuffix);
                    expRuleDetailModel.setFunValue(Integer.parseInt(ruleTemplateModel.getFunValue()));
                    break;
            }
        }

        expRuleDetailModel.setRuleTblType(ruleTblType);
        expRuleDetailModel.setDataUnit(ruleTemplateModel.getDataUnit());
        expRuleDetailModel.setDataPeriod(Integer.parseInt(ruleTemplateModel.getDataPeriod()));
        expRuleDetailModel.setSchemaName(ruleTemplateModel.getSchemaName());
        expRuleDetailModel.setRuleTbl(ruleTemplateModel.getRuleTbl());
        expRuleDetailModel.setColList(ruleTemplateModel.getColList());
        expRuleDetailModel.setRuleTYpe(Integer.parseInt(ruleTemplateModel.getRuleType()));
        expRuleDetailModel.setRowRange(ruleTemplateModel.getRowRange());
        expRuleDetailModel.setSplitKey(ruleTemplateModel.getSplitKey());
        expRuleDetailModel.setInitRow(Integer.parseInt(ruleTemplateModel.getInitRow()));
        expRuleDetailModel.setRuleDetailId("rule_detail_" + SnowFlakeUtil.getNextId());
        expRuleDetailModel.setUpdate_time(new Date());
        expRuleDetailModel.setRuleId(ruleId);

        expRuleDetailService.save(expRuleDetailModel);
        return (long) expRuleModel.getId();
    }

    @Transactional
    @Override
    public void batchDelete(Set<Long> ids) throws Exception {
        Set<String> ruleIds = this.getRuleIds(ids);
        expRuleDao.batchDelete(ids);
        expRuleDetailService.batchDeleteById(ruleIds);
    }

    public Set<String> getRuleIds(Set<Long> ids) {
        return expRuleDao.findExpRuleIdsByIds(ids);
    }
}
